/**
 ******************************************************************************
 * @file           : bsp_ds18b20.c
 * @brief          : DS18B20 Temperature Sensor Driver (STM32H7xx)
 ******************************************************************************
 * @attention
 *
 * DS18B20温度传感器驱动实现文件
 * 单总线通信协议
 *
 ******************************************************************************
 */

/* Includes ------------------------------------------------------------------*/
#include "./Devices/DS18B20/bsp_ds18b20.h"
#include "./Devices/DS18B20/bsp_ds18b20_config.h"

/* Private includes ----------------------------------------------------------*/
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
#define DS18B20_CMD_SKIP_ROM        0xCC    /*!< 跳过ROM命令 */
#define DS18B20_CMD_CONVERT_T       0x44    /*!< 温度转换命令 */
#define DS18B20_CMD_READ_SCRATCHPAD 0xBE    /*!< 读取暂存器命令 */
#define DS18B20_CMD_WRITE_SCRATCHPAD 0x4E   /*!< 写入暂存器命令 */

/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
static volatile uint8_t sg_ds18b20_initialized = 0;  /*!< 初始化标志 */
static volatile DS18B20_Resolution_e sg_resolution = DS18B20_RES_12BIT;  /*!< 分辨率 */

/* Private function prototypes -----------------------------------------------*/
static void ds18b20_gpio_init(void);
static void ds18b20_gpio_deinit(void);
static void ds18b20_set_output(void);
static void ds18b20_set_input(void);
static uint8_t ds18b20_read_bit(void);
static void ds18b20_write_bit(uint8_t bit);
static uint8_t ds18b20_read_byte(void);
static void ds18b20_write_byte(uint8_t byte);
static DS18B20_Error_e ds18b20_reset(void);
static uint8_t ds18b20_crc8(uint8_t *data, uint8_t len);

/* Private functions ---------------------------------------------------------*/

/**
 * @brief       DS18B20 GPIO初始化
 *
 * @param       无
 *
 * @retval      无
 */
static void ds18b20_gpio_init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};

    DS18B20_GPIO_CLK_ENABLE();

    GPIO_InitStruct.Pin = DS18B20_GPIO_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(DS18B20_GPIO_PORT, &GPIO_InitStruct);

    /* 初始状态：高电平 */
    HAL_GPIO_WritePin(DS18B20_GPIO_PORT, DS18B20_GPIO_PIN, GPIO_PIN_SET);
}

/**
 * @brief       DS18B20 GPIO反初始化
 *
 * @param       无
 *
 * @retval      无
 */
static void ds18b20_gpio_deinit(void)
{
    HAL_GPIO_DeInit(DS18B20_GPIO_PORT, DS18B20_GPIO_PIN);
}

/**
 * @brief       设置DS18B20为输出模式
 *
 * @param       无
 *
 * @retval      无
 */
static void ds18b20_set_output(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};

    GPIO_InitStruct.Pin = DS18B20_GPIO_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(DS18B20_GPIO_PORT, &GPIO_InitStruct);
}

/**
 * @brief       设置DS18B20为输入模式
 *
 * @param       无
 *
 * @retval      无
 */
static void ds18b20_set_input(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};

    GPIO_InitStruct.Pin = DS18B20_GPIO_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(DS18B20_GPIO_PORT, &GPIO_InitStruct);
}

/**
 * @brief       读取一个比特
 *
 * @param       无
 *
 * @retval      uint8_t - 比特值（0或1）
 */
static uint8_t ds18b20_read_bit(void)
{
    uint8_t bit = 0;

    ds18b20_set_output();
    HAL_GPIO_WritePin(DS18B20_GPIO_PORT, DS18B20_GPIO_PIN, GPIO_PIN_RESET);
    for(int i = 0; i < 3; i++) __NOP();

    ds18b20_set_input();
    for(int i = 0; i < 14; i++) __NOP();

    if(HAL_GPIO_ReadPin(DS18B20_GPIO_PORT, DS18B20_GPIO_PIN) == GPIO_PIN_SET)
    {
        bit = 1;
    }

    for(int i = 0; i < 40; i++) __NOP();

    return bit;
}

/**
 * @brief       写入一个比特
 *
 * @param[in]   bit - 比特值
 *
 * @retval      无
 */
static void ds18b20_write_bit(uint8_t bit)
{
    ds18b20_set_output();
    HAL_GPIO_WritePin(DS18B20_GPIO_PORT, DS18B20_GPIO_PIN, GPIO_PIN_RESET);

    if(bit)
    {
        for(int i = 0; i < 10; i++) __NOP();
        ds18b20_set_input();
        for(int i = 0; i < 55; i++) __NOP();
    }
    else
    {
        for(int i = 0; i < 60; i++) __NOP();
        ds18b20_set_input();
        for(int i = 0; i < 10; i++) __NOP();
    }
}

/**
 * @brief       读取一个字节
 *
 * @param       无
 *
 * @retval      uint8_t - 字节值
 */
static uint8_t ds18b20_read_byte(void)
{
    uint8_t byte = 0;

    for(int i = 0; i < 8; i++)
    {
        byte >>= 1;
        if(ds18b20_read_bit())
        {
            byte |= 0x80;
        }
    }

    return byte;
}

/**
 * @brief       写入一个字节
 *
 * @param[in]   byte - 字节值
 *
 * @retval      无
 */
static void ds18b20_write_byte(uint8_t byte)
{
    for(int i = 0; i < 8; i++)
    {
        ds18b20_write_bit(byte & 0x01);
        byte >>= 1;
    }
}

/**
 * @brief       DS18B20复位
 *
 * @param       无
 *
 * @retval      DS18B20_Error_e - 错误码
 */
static DS18B20_Error_e ds18b20_reset(void)
{
    uint32_t timeout;

    ds18b20_set_output();
    HAL_GPIO_WritePin(DS18B20_GPIO_PORT, DS18B20_GPIO_PIN, GPIO_PIN_RESET);
    HAL_Delay(1);

    ds18b20_set_input();
    timeout = DS18B20_TIMEOUT_US * 10;
    while(HAL_GPIO_ReadPin(DS18B20_GPIO_PORT, DS18B20_GPIO_PIN) == GPIO_PIN_SET && timeout--);
    if(timeout == 0) return DS18B20_ERROR_TIMEOUT;

    timeout = DS18B20_TIMEOUT_US * 10;
    while(HAL_GPIO_ReadPin(DS18B20_GPIO_PORT, DS18B20_GPIO_PIN) == GPIO_PIN_RESET && timeout--);
    if(timeout == 0) return DS18B20_ERROR_TIMEOUT;

    return DS18B20_OK;
}

/**
 * @brief       CRC8校验
 *
 * @param[in]   data - 数据指针
 * @param[in]   len - 数据长度
 *
 * @retval      uint8_t - CRC值
 */
static uint8_t ds18b20_crc8(uint8_t *data, uint8_t len)
{
    uint8_t crc = 0;

    for(uint8_t i = 0; i < len; i++)
    {
        uint8_t byte = data[i];
        for(uint8_t j = 0; j < 8; j++)
        {
            uint8_t temp = (crc ^ byte) & 1;
            crc >>= 1;
            if(temp)
            {
                crc ^= 0x8C;
            }
            byte >>= 1;
        }
    }

    return crc;
}

/* Public functions ----------------------------------------------------------*/

DS18B20_Error_e ds18b20_init(void)
{
    if(sg_ds18b20_initialized)
    {
        return DS18B20_OK;
    }

    ds18b20_gpio_init();
    sg_ds18b20_initialized = 1;
    sg_resolution = DS18B20_RES_12BIT;

    log_i("DS18B20 initialized");
    return DS18B20_OK;
}

void ds18b20_deinit(void)
{
    if(!sg_ds18b20_initialized)
    {
        return;
    }

    ds18b20_gpio_deinit();
    sg_ds18b20_initialized = 0;

    log_i("DS18B20 deinitialized");
}

DS18B20_Error_e ds18b20_read_temperature(float *temperature)
{
    DS18B20_Error_e ret;
    uint8_t scratchpad[9];
    uint8_t crc;
    int16_t raw_temp;

    if(!sg_ds18b20_initialized)
    {
        log_e("DS18B20 not initialized");
        return DS18B20_ERROR_NOT_INIT;
    }

    if(temperature == NULL)
    {
        log_e("Invalid pointer");
        return DS18B20_ERROR_PARAM;
    }

    /* 复位 */
    ret = ds18b20_reset();
    if(ret != DS18B20_OK)
    {
        log_e("DS18B20 reset failed");
        return ret;
    }

    /* 跳过ROM */
    ds18b20_write_byte(DS18B20_CMD_SKIP_ROM);

    /* 启动温度转换 */
    ds18b20_write_byte(DS18B20_CMD_CONVERT_T);
    HAL_Delay(800);  /* 等待转换完成 */

    /* 复位 */
    ret = ds18b20_reset();
    if(ret != DS18B20_OK)
    {
        return ret;
    }

    /* 跳过ROM */
    ds18b20_write_byte(DS18B20_CMD_SKIP_ROM);

    /* 读取暂存器 */
    ds18b20_write_byte(DS18B20_CMD_READ_SCRATCHPAD);

    for(int i = 0; i < 9; i++)
    {
        scratchpad[i] = ds18b20_read_byte();
    }

    /* CRC校验 */
    crc = ds18b20_crc8(scratchpad, 8);
    if(crc != scratchpad[8])
    {
        log_e("CRC check failed");
        return DS18B20_ERROR_CRC;
    }

    /* 转换温度 */
    raw_temp = (scratchpad[1] << 8) | scratchpad[0];
    *temperature = raw_temp / 16.0f;

    log_d("Temperature: %.4f°C", *temperature);
    return DS18B20_OK;
}

DS18B20_Error_e ds18b20_set_resolution(DS18B20_Resolution_e resolution)
{
    if(!sg_ds18b20_initialized)
    {
        return DS18B20_ERROR_NOT_INIT;
    }

    if(resolution > DS18B20_RES_12BIT)
    {
        return DS18B20_ERROR_PARAM;
    }

    sg_resolution = resolution;
    log_i("DS18B20 resolution set to %d-bit", 9 + resolution);
    return DS18B20_OK;
}

DS18B20_Error_e ds18b20_get_resolution(DS18B20_Resolution_e *resolution)
{
    if(!sg_ds18b20_initialized)
    {
        return DS18B20_ERROR_NOT_INIT;
    }

    if(resolution == NULL)
    {
        return DS18B20_ERROR_PARAM;
    }

    *resolution = sg_resolution;
    return DS18B20_OK;
}

void ds18b20_print_status(void)
{
    float temperature;

    log_i("=== DS18B20 Status ===");
    log_i("Initialized: %s", sg_ds18b20_initialized ? "Yes" : "No");
    log_i("Resolution: %d-bit", 9 + sg_resolution);

    if(ds18b20_read_temperature(&temperature) == DS18B20_OK)
    {
        log_i("Temperature: %.4f°C", temperature);
    }
    else
    {
        log_e("Failed to read DS18B20");
    }
}
